//
//  HNGroundLogic.m
//  HeroNuts
//
//  Created by Gelford on 11-4-14.
//  Copyright 2011年 __MyCompanyName__. All rights reserved.
//

#import "HNGroundLogic.h"
#import "HNGround.h"
#import "HNLogicPosition.h"

#define MOVE_TEST 


@implementation HNGroundLogic

static HNGroundLogic * sharedGroundLogic_ = nil;

#pragma mark dealloc,alloc,init

- (void) dealloc
{
  [super dealloc];
}

-(id) init
{
	if( (self = [super init]) ) 
	{
    int MapData[MAP_HEIGHT * MAP_WIDTH] = 
    {
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    };
    memcpy(mapData_,MapData,MAP_SIZE*sizeof(int));
	}
	return self;	
}

+(id)alloc
{
	NSAssert(sharedGroundLogic_ == nil, @"Attempted to allocate a second instance of a singleton.");
	return [super alloc];
}

#pragma mark singleton

+ (HNGroundLogic *) sharedGroundLogic
{
	if (!sharedGroundLogic_)
    sharedGroundLogic_ = [[HNGroundLogic alloc] init];
  
	return sharedGroundLogic_;
}

#pragma mark private methods

- (void)clearOutputMap
{
  memset(outputMap_,0,MAP_SIZE*sizeof(int));
}

- (void)moveActor:(int)destination ofHexSize:(NSInteger)hexSize
{
  mapData_[actorPosition_] = 1;
  mapData_[destination] = 0;
  
  actorMap_[destination] = actorMap_[actorPosition_];
  actorMap_[actorPosition_] = nil;
  
  if (hexSize == 2) {
    mapData_[actorPosition_+1] = 1;
    mapData_[destination+1] = 0;
    
    actorMap_[destination+1] = actorMap_[actorPosition_+1];
    actorMap_[actorPosition_+1] = nil;
  }
}


#pragma mark CreateActor,

- (void) addActor:(HNActor *)anActor inPosition:(CGPoint)actorPosition
{
  HNGroundCell *aGroundCell = [[HNGroundCell alloc] initWithActor:anActor];
  int newPosition = CreatePoint(actorPosition.x, actorPosition.y);
  
  mapData_[newPosition] = 0;
  actorMap_[newPosition] = aGroundCell;
  if (anActor.hexSize == 2) {
    mapData_[newPosition+1] = 0;
    actorMap_[newPosition+1] = aGroundCell;
  }
}

#pragma mark GetAreaToPrint

- (NSMutableArray *)getWalkAreaFrom:(CGPoint)actorPosition
{
  int actorLogicPosition = CreatePoint(actorPosition.x, actorPosition.y);
  NSInteger hexSize = actorMap_[actorLogicPosition].actor.hexSize;
  NSInteger step = actorMap_[actorLogicPosition].actor.speed;
  actorPosition_ = actorLogicPosition;
  NSMutableArray *walkArea = [NSMutableArray array];

  PrintOutMap(mapData_);
  int arrayCanWalk[MAP_SIZE] = {0};
  
  [self clearOutputMap];
  if (hexSize == 1) {
    GetCanWalk(mapData_, actorLogicPosition, outputMap_, step, arrayCanWalk);
  }else{
    GetCanWalk2(mapData_, actorLogicPosition, outputMap_, step, arrayCanWalk);
  }
  memcpy(arrayOfArea_, arrayCanWalk, MAP_SIZE*sizeof(int));
  
  for (int i = 0; i < MAP_SIZE; i++) 
  {
    if (arrayCanWalk[i] != 0) {
      HNLogicPosition *aLogicPosi = [[HNLogicPosition alloc] init];
      aLogicPosi.position = CGPointMake(GetX(i), GetY(i));
      [walkArea addObject:aLogicPosi];
      [aLogicPosi release];
    }
  }
  
  return walkArea;
}

- (NSMutableArray *)getFlyAreaFrom:(CGPoint)actorPosition
{
  int actorLogicPosition = CreatePoint(actorPosition.x, actorPosition.y);
  NSInteger hexSize = actorMap_[actorLogicPosition].actor.hexSize;
  NSInteger step = actorMap_[actorLogicPosition].actor.speed;
  actorPosition_ = actorLogicPosition;
  NSMutableArray *flyArea = [NSMutableArray array];
  int arrayCanFly[MAP_SIZE] = {0};
  
  [self clearOutputMap];
  if (hexSize == 1) {
    GetCanFly(mapData_, actorLogicPosition, outputMap_, step, arrayCanFly);
  }else{
    GetCanFly2(mapData_, actorLogicPosition, outputMap_, step, arrayCanFly);
  }
  memcpy(arrayOfArea_, arrayCanFly, MAP_SIZE);
  
  for (int i = 0; i < MAP_SIZE; i++) 
  {
    if (arrayCanFly[i] != 0) {
      HNLogicPosition *aLogicPosi = [[HNLogicPosition alloc] init];
      aLogicPosi.position = CGPointMake(GetX(i), GetY(i));
      [flyArea addObject:aLogicPosi];
      [aLogicPosi release];
    }
  }
  
  return flyArea;
}

#pragma mark GetRoute

- (NSMutableArray *)getWalkRoute:(CGPoint)destination
{
  NSInteger hexSize = actorMap_[actorPosition_].actor.hexSize;
  if (hexSize == 2) {
    int destinationTemp = CreatePoint(destination.x, destination.y);
    if (destination.x == MAP_WIDTH-1) {
      destination.x--;
    }
    else if (mapData_[destinationTemp+1] == 0) {
      destination.x--;
    }
  }
  
  int logicDestination = CreatePoint(destination.x, destination.y);
  NSMutableArray *arrayOfRouteInt = [NSMutableArray array];
  NSMutableArray *arrayOfRoutePoint = [NSMutableArray array];

  GetWalkRoute(mapData_, actorPosition_, logicDestination, outputMap_, arrayOfRouteInt);
  
  for (NSNumber *aNumber in arrayOfRouteInt) 
  {
    CGPoint aPoint = CGPointMake(GetX([aNumber intValue]), GetY([aNumber intValue]));

    HNLogicPosition *aLogicPosition = [[HNLogicPosition alloc] initWithPoint:aPoint];
    [arrayOfRoutePoint addObject:aLogicPosition];
    [aLogicPosition release];
  }
  
  [self moveActor:logicDestination ofHexSize:hexSize];
  return arrayOfRoutePoint;
}

#pragma mark -Some Other Methods

- (HNActor *)actorAtPosition: (CGPoint)position
{
  int actorPosition = CreatePoint(position.x, position.y);
  HNGroundCell *actorCell = actorMap_[actorPosition];
  return actorCell.actor;
}

- (BOOL)currentActorCanReachPosition: (CGPoint)position
{
//#ifdef MOVE_TEST
//    return YES;
//#else
//    return NO;
//#endif
  int destinationPosition = CreatePoint(position.x, position.y);
  if (arrayOfArea_[destinationPosition] == 0) {
    return NO;
  }
  else{
    return YES;
  }
}

- (NSMutableArray *)reachablePositionsAroundActor: (HNActor *)actor
{
  int targetPosition = CreatePoint(actor.position.x, actor.position.y);
  NSMutableArray *arrayOfReachablePostion = [NSMutableArray array];
  
  for (int i = 0; i < DIRECTION_COUNT; i ++) {
    int thePosition = GetNearPoint(targetPosition, i);
    if (thePosition == -1){
      continue;
    }
    if(outputMap_[thePosition] == 0){
      continue;
    }
    HNLogicPosition *aLogicPosition = [[HNLogicPosition alloc] 
                                       initWithPoint:CGPointMake(GetX(thePosition), GetY(thePosition))];
    [arrayOfReachablePostion addObject:aLogicPosition];
    [aLogicPosition release];
  }
  if ([arrayOfReachablePostion count] == 0) {
    return nil;
  }
  return arrayOfReachablePostion;
}

- (int)directionFromPosition:(CGPoint)position toActor:(HNActor *)actor
{
  int targetPosition = CreatePoint(actor.position.x, actor.position.y);
  int theNearPosition = CreatePoint(position.x, position.y);
  
  for (int i = 0; i < DIRECTION_COUNT; i ++) {
    int thePosition = GetNearPoint(theNearPosition, i);
    if (thePosition == targetPosition) {
      if (i == RIGHT_TOP) {
        i = RIGHT_BOTTOM;
      }
      else if(i == RIGHT_BOTTOM){
        i = RIGHT_TOP;
      }
      else if (i == LEFT_TOP) {
        i = LEFT_BOTTOM;
      }
      else if (i == LEFT_BOTTOM){
        i = LEFT_TOP;
      }
      return i;
    }
  }
  return -1;
}

- (BOOL)isPosition:(CGPoint)position occupiedByActor:(HNActor*)actor
{
  if (actor.hexSize == 1) {
    if (position.x == actor.position.x && position.y == actor.position.y) {
      return YES;
    }
  }
  else if (actor.hexSize == 2) {
    if (position.x == actor.position.x && position.y == actor.position.y) {
      return YES;
    }
    else if(position.x == (actor.position.x+1) && position.y == actor.position.y){
      return YES;
    }
  }
  return NO;
}

@end
